package junit;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;


import parser.DataParser;
import parser.Case;
import parser.DataParser;
import parser.EffortEstimator;

public class TestAlgo {
	static double[][] data = {	
		{0.75, 0.88, 1.00, 1.15, 1.40, 0},	//Required software reliability
		{0   , 0.94, 1.00, 1.08, 1.16, 0},	//Data base size
		{0.70, 0.85, 1.00, 1.15, 1.30, 1.65},	//Process complexity
		{0   , 0   , 1.00, 1.11, 1.30, 1.66},	//Time constraint for CPU
		{0   , 0   , 1.00, 1.06, 1.21, 1.56},	//Main memory constraint
		{0   , 0.87, 1.00, 1.15, 1.30, 0},	//Machine volatility
		{0   , 0.87, 1.00, 1.07, 1.15, 0},	//Turnaround time 
		{1.46, 1.19, 1.00, 0.86, 0.71, 0},	//Analysts capability
		{1.29, 1.13, 1.00, 0.91, 0.82, 0},	//Application experience
		{1.42, 1.17, 1.00, 0.86, 0.70, 0},	//Programmers capability
		{1.21, 1.10, 1.00, 0.90, 0   , 0},	//Virtual machine experience
		{1.14, 1.07, 1.00, 0.95, 0   , 0},	//Language experience
		{1.24, 1.10, 1.00, 0.91, 0.82, 0},	//Modern programming practices
		{1.24, 1.10, 1.00, 0.91, 0.83, 0},	//Use of software tools
		{1.23, 1.08, 1.00, 1.04, 1.10, 0}	//Schedule constraint
	};

	private DataParser dp;
	private ArrayList<String> projects;
	private static int NBR_OF_MULT = 17; // data.length + 2, for the last two fields LOC and ACT_EFFORT.
	public int total;

	public static void main(String args[]){
		long start = System.currentTimeMillis();
		TestAlgo ta = new TestAlgo("data.txt");
		DecimalFormat df = new DecimalFormat("###.#####");
		int in_range = 0;
		int cocomo_in_range = 0;
		int sum_in_range = 0;

		for(int i = 0; i < ta.getNbrOfLines(); i++){
			String project = ta.getProject(i);
			
			String[] tokens = ta.getProject(i).split(",");
			
			double kloc = Double.parseDouble(tokens[tokens.length - 2]);
			double real_effort = Double.parseDouble(tokens[tokens.length - 1]);

			double threshold = 0.5;


			double est_effort = ta.estEffort(project, threshold, kloc, i);
			double cocomo_est = ta.cocomo(project, kloc);
			
			double diff = Math.abs(real_effort - est_effort);
			double cocomo_diff = Math.abs(real_effort - cocomo_est);
			
			int perc = (int) ((diff/real_effort) * 100);
			int cocomo_perc = (int) ((cocomo_diff/real_effort) * 100);

			if(perc <= 30){
				in_range++;
			}
			
			if(cocomo_perc <= 30){
				cocomo_in_range++;
			}
			
			if(cocomo_perc <= 30 || perc <= 30) {
				sum_in_range++;
			}
			
			if(est_effort != 0)
				System.out.println("Project " + i + "\tCOCOMO est: " + df.format(cocomo_est) + "\tReal effort: " + real_effort + "\tEst. effort: " + df.format(est_effort) + "\t\tDeviation: " + perc + " %" + "\t\tDeviation cocomo: " + cocomo_perc + " %" + "\t\tSum of deviation: " + ((cocomo_perc + perc) / 2) + " %");
		}
		
		long stop = System.currentTimeMillis();
		
		System.out.println("Projects in range (of " + (60) + "): " + in_range);
		System.out.println("First algorithm:\t" + ((double) in_range) / 60);
		System.out.println("COCOMO algorithm:\t" + ((double) cocomo_in_range) / 60);
		System.out.println("COCOMO OR ALGORITHM:\t" + ((double) sum_in_range) / 60);
		System.out.println("Time: " + (stop - start) + " ms.");
	}

	public TestAlgo(String fname){
		dp = new DataParser(fname);
		NBR_OF_MULT = dp.getNbrOfCols();

		projects = new ArrayList<String>();

		// read data.txt to ArrayList<String> projects
		int nbrLines = dp.getNbrOfLines();
		BufferedReader in = null;

		try {
			in = new BufferedReader(new FileReader(fname));
		} catch (FileNotFoundException e) {
			System.out.println(fname + " not found.");
		}

		for(int i = 0; i <= nbrLines; i++){
			String line = null;

			try {
				line = in.readLine();
			} catch(IOException fe) {
				System.out.println("Could not read from " + fname);
			}

			projects.add(line);
		}

	}

	public String getProject(int i){
		return projects.get(i);
	}
	
	public double cocomo(String project, double kloc){
		return dp.COCOMOestimation(project, kloc);
	}

	public double estEffort(String project, double threshold, double kloc, int omit){
		total = 0;
		EffortEstimator ee = new EffortEstimator(kloc); //Kilo Lines of Code

		double[][] parsed = dp.parse();

		String[] s = project.split(",");	

		double[] pNew 		= new double[NBR_OF_MULT-1];
		double[] pExisting 	= new double[NBR_OF_MULT-1];

		double[] min 		= dp.getMin();
		double[] max		= dp.getMax();

		int nbrOfLines = dp.getNbrOfLines();

		for(int i = 0; i < nbrOfLines; i++) {
			for(int j = 0; j < NBR_OF_MULT-2; j++) {
				int a = DataParser.mapLevelToColumn(s[j]);
				pNew[j] 	= data[j][a];
				pExisting[j]	= parsed[i][j];
			}
			
			pNew[NBR_OF_MULT-2]=kloc;
			pExisting[NBR_OF_MULT-2]=parsed[i][NBR_OF_MULT-2];
			
			//double similarity = dp.calculateSimilarity(pNew, pExisting, min, max);
			double similarity = DataParser.calculateSimilarity(pNew, pExisting, min, max);
			
			if((similarity >= threshold) && (omit != i)) {
				Case c = new Case(similarity, parsed[i][NBR_OF_MULT-2], parsed[i][NBR_OF_MULT-1]);
				ee.addCase(c);
				total++;
			}
		}

		double result = ee.calculate();

		return result;
	}

	public int getNbrOfLines(){
		return dp.getNbrOfLines();
	}
}